package gee

import (
	"fmt"
	"strings"
)

type router struct {
	root     map[string]*node
	handlers map[string]HandlerFunc
}

func newRouter() *router {
	return &router{
		handlers: make(map[string]HandlerFunc),
		root:     make(map[string]*node),
	}
}

func (r *router) addRouter(method string, pattern string, handlerFunc HandlerFunc) {
	//路由分组
	parts := parsePattern(pattern)
	method = strings.ToUpper(method)
	var key strings.Builder
	_, ok := r.root[method]
	if !ok {
		r.root[method] = &node{}
	}
	r.root[method].insert(pattern, parts, 0)
	key.WriteString(method)
	key.WriteString("-")
	key.WriteString(pattern)
	r.handlers[key.String()] = handlerFunc
}

func (r *router) getRouter(method string, pattern string) (*node, map[string]string) {
	root, ok := r.root[method]
	if !ok {
		return nil, nil
	}
	searchParts := parsePattern(pattern)
	n := root.search(searchParts, 0)
	if n == nil {
		return nil, nil
	}
	params := make(map[string]string)
	parts := parsePattern(n.pattern)
	for index, part := range parts {
		if part[0] == ':' {
			params[part[1:]] = searchParts[index]
		}
		if part[0] == '*' && len(part) > 1 {
			params[part[1:]] = strings.Join(searchParts[index:], "/")
			break
		}
	}

	return n, params
}

func (r *router) handle404Func(c *Context) {
	if handleFunc, ok := r.handlers[strings.ToUpper(c.Method)+"-404"]; ok {
		handleFunc(c)
		return
	}
	c.SetStatusCode(404)
	c.Res.WriteHeader(404)
	fmt.Fprintf(c.Res, "404 not found")
}

func (r *router) handle(c *Context) {
	n, params := r.getRouter(strings.ToUpper(c.Method), c.Path)
	c.Params = params
	if n == nil || n.pattern == "" {
		c.handlers = append(c.handlers, r.handle404Func)
		c.Next()
		return
	}
	var key strings.Builder
	key.WriteString(strings.ToUpper(c.Method))
	key.WriteString("-")
	key.WriteString(n.pattern)
	if handleFunc, ok := r.handlers[key.String()]; ok {
		c.handlers = append(c.handlers, handleFunc)
		c.Next()
		return
	}
	c.handlers = append(c.handlers, r.handle404Func)
	c.Next()
	return

}
